package com.twotwoshop.service.user.service.Impl;


import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.twotwoshop.commom.redis.RedisConstants;
import com.twotwoshop.domin.common.dtos.ResponseResult;
import com.twotwoshop.domin.common.enums.AppHttpCodeEnum;
import com.twotwoshop.domin.user.pojos.ApUser;
import com.twotwoshop.domin.user.pojos.Fan;
import com.twotwoshop.domin.user.pojos.Follow;
import com.twotwoshop.domin.user.vo.FollowVo;
import com.twotwoshop.service.user.mapper.FanMapper;
import com.twotwoshop.service.user.mapper.FollowMapper;
import com.twotwoshop.service.user.mapper.UserMapper;
import com.twotwoshop.service.user.service.IFanService;
import com.twotwoshop.service.user.service.IFollowService;
import com.twotwoshop.util.thread.AppThreadLocalUtil;
import lombok.RequiredArgsConstructor;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * APP用户关注信息表 服务实现类
 * </p>
 *
 * @author 王帅
 * @since 2024-12-20
 */
@Service
@RequiredArgsConstructor
public class FollowServiceImpl extends ServiceImpl<FollowMapper, Follow> implements IFollowService {

    private final FollowMapper followMapper;

    private final FanMapper fanMapper;

    private final UserMapper userMapper;

    private final StringRedisTemplate stringRedisTemplate;

    /**
     * 关注用户
     *
     * @param follow
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public ResponseResult followUserById(Follow follow) {


        try {
            //1.检查参数
            if (follow.getFollowId()==null || follow.getFollowId()<=0){
                return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID,"关注用户id为空");
            }

            Integer id = AppThreadLocalUtil.getUser().getId();

            //1.1先查询该用户是否已经被关注
            Double score = stringRedisTemplate.opsForZSet().score(RedisConstants.USER_FOLLOW_KEY + id, String.valueOf(follow.getFollowId()));
            if (score!=null){
                return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID,"该用户已被关注");
            }

            Double score1 = stringRedisTemplate.opsForZSet().score(RedisConstants.USER_FAN_KEY+ follow.getFollowId(), String.valueOf(id));
            if (score1!=null){
                return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID,"该用户已被关注1");
            }


            //2.关注商家
            Boolean add = stringRedisTemplate.opsForZSet().add(RedisConstants.USER_FOLLOW_KEY + id, follow.getFollowId().toString(), System.currentTimeMillis());
            if (!add){
                return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID);
            }

            //3.为商家添加粉丝
            Boolean add1 = stringRedisTemplate.opsForZSet().add(RedisConstants.USER_FAN_KEY + follow.getFollowId(), id.toString(), System.currentTimeMillis());
            if (!add1){
                return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID);
            }


            //异步关注信息进数据库
            saveFollowAndFan(id,follow.getFollowId(),System.currentTimeMillis());
        } catch (Exception e) {
            throw new RuntimeException(e);
        }


        return ResponseResult.okResult(AppHttpCodeEnum.SUCCESS);
    }

    /**
     * 异步数据库取关用户
     *
     * @param follow
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public ResponseResult cancelUserById(Follow follow) {

        try {
            // 1. 检查参数
            if (follow.getFollowId() == null || follow.getFollowId() <= 0) {
                return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID, "关注用户id为空");
            }

            Integer id = AppThreadLocalUtil.getUser().getId();

            // 1.1 先查询该用户是否已经被关注
            Double score = stringRedisTemplate.opsForZSet().score(RedisConstants.USER_FOLLOW_KEY + id, String.valueOf(follow.getFollowId()));
            if (score == null) {
                return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID, "该关注信息不存在");
            }

            Double score1 = stringRedisTemplate.opsForZSet().score(RedisConstants.USER_FAN_KEY + follow.getFollowId(), String.valueOf(id));
            if (score1 == null) {
                return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID, "该关注信息不存在");
            }

            // 2. 取关商家
            Long remove = stringRedisTemplate.opsForZSet().remove(RedisConstants.USER_FOLLOW_KEY + id, follow.getFollowId().toString());
            if (remove == null || remove <= 0) {
                return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID, "redis取关失败");
            }

            // 3. 为商家减少粉丝
            Long remove1 = stringRedisTemplate.opsForZSet().remove(RedisConstants.USER_FAN_KEY + follow.getFollowId(), id.toString());
            if (remove1 == null || remove1 <= 0) {
                return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID, "redis取关失败1");
            }

            // 异步删除关注信息进数据库
            removeFollowAndFan(id, follow.getFollowId());
        } catch (Exception e) {
            throw new RuntimeException("取关用户失败", e);
        }

        return ResponseResult.okResult(AppHttpCodeEnum.SUCCESS);
    }


    /**
     * 查询关注状态
     *
     * @param id
     * @return
     */
    @Override
    public ResponseResult checkUserById(Integer id) {

        //1.检查参数
        if (id == null || id <= 0) {
            return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID,"用户id为空");
        }

        Integer userId = AppThreadLocalUtil.getUser().getId();

        //2.查询关注信息
        Double score = stringRedisTemplate.opsForZSet().score(RedisConstants.USER_FOLLOW_KEY + userId, String.valueOf(id));
        if (score == null) {
            return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID,"未关注");
        }

        return ResponseResult.okResult(AppHttpCodeEnum.SUCCESS);
    }


    /**
     * 获取关注列表
     *
     * @return
     */
    @Override
    public ResponseResult listUserById() {

        //1.获取当前用户id
        Integer userId = AppThreadLocalUtil.getUser().getId();


        //2.获取关注列表id
        Set<String> followIdList = stringRedisTemplate.opsForZSet().rangeByScore(RedisConstants.USER_FOLLOW_KEY + userId, 0, Long.MAX_VALUE);
        if (followIdList == null || followIdList.size() <= 0) {
            return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID,"没有关注");
        }

        //3.根据用户id集合查询用户数据
        List<Long> collect = followIdList.stream().map(Long::valueOf).collect(Collectors.toList());

        //查询关注用户的信息
        List<ApUser> apUsersList = userMapper.selectBatchIds(collect);
        if (apUsersList == null || apUsersList.size() <= 0) {
            return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID,"查询关注信息失败");
        }

        //拷贝用户基本信息返回到关注列表
        List<FollowVo> followVos = BeanUtil.copyToList(apUsersList, FollowVo.class);

        for (FollowVo followVo : followVos) {



            //查出每个卖家的粉丝数
            Long fanSize = stringRedisTemplate.opsForZSet().size(RedisConstants.USER_FAN_KEY + followVo.getId());
            if (fanSize == null) {
                followVo.setFanCount(0L);
            }

            followVo.setFanCount(fanSize);

        }

        return ResponseResult.okResult(followVos);
    }


    /**
     * 异步提交线程池同步数据库
     * @param id
     * @param followId
     */
    @Async("twotwoUploadExecutor")
    @Transactional(rollbackFor = Exception.class)
    void removeFollowAndFan(Integer id, Integer followId) {

        LambdaQueryWrapper<Follow> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Follow::getFollowId, followId)
                    .eq(Follow::getUserId, id);

        //1.先查询
        Follow follow = followMapper.selectOne(queryWrapper);
        if (follow==null){
            throw new RuntimeException("关注信息数据库不存在");
        }

        int delete = followMapper.delete(queryWrapper);
        if (delete<=0){
            throw new RuntimeException("关注信息数据库删除失败");
        }


        LambdaQueryWrapper<Fan> queryWrapper1 = new LambdaQueryWrapper<>();
        queryWrapper1.eq(Fan::getUserId, followId)
                    .eq(Fan::getFansId,id);

        Fan follow1 = fanMapper.selectOne(queryWrapper1);
        if (follow1==null){
            throw new RuntimeException("粉丝信息数据库不存在");
        }

        int delete1 = fanMapper.delete(queryWrapper1);
        if (delete1<=0){
            throw new RuntimeException("关注信息数据库删除失败1");
        }

    }

    /**
     * 异步提交线程池同步数据库
     * @param id
     * @param followId
     */
    @Async("twotwoUploadExecutor")
    @Transactional(rollbackFor = Exception.class)
    void saveFollowAndFan(Integer id, Integer followId, Long time) {

        Follow follow = new Follow();
        follow.setUserId(id);
        follow.setFollowId(followId);

        // 将毫秒时间戳转换为 Instant
        Instant instant = Instant.ofEpochMilli(time);
        // 将 Instant 转换为 LocalDateTime
        LocalDateTime localDateTime = LocalDateTime.ofInstant(instant, ZoneId.systemDefault());
        follow.setCreatedTime(localDateTime);

        int insert = followMapper.insert(follow);
        if (insert != 1){
            throw new RuntimeException("异步同步用户关注数据失败");
        }


        Fan fan = new Fan();
        fan.setUserId(followId);
        fan.setFansId(id);
        fan.setCreatedTime(localDateTime);
        int insert1 = fanMapper.insert(fan);
        if (insert1 != 1){
            throw new RuntimeException("异步同步用户关注数据失败");
        }

    }
}
